package org.apache.ocean;

import com.ibm.icu.text.Collator;
import java.util.Comparator;
import org.apache.ocean.server.FieldType;
import org.apache.ocean.server.LocalizedFieldType;

/**
 *
 * @author jasonr
 */
public class OceanDocumentComparator implements Comparator<OceanDocument> {
  public static final int NULLS_ARE_INVALID = 0;
  public static final int NULLS_ARE_LEAST = 1;
  public static final int NULLS_ARE_GREATEST = 2;
  public static final int ASCENDING_ORDER = 1;
  public static final int DESCENDING_ORDER = 0;
  
  public int nullBehavior = NULLS_ARE_LEAST;
  int[] nullFields;
  CSortFields sortFields;
  Collator[] collators;
  IndexSchema indexSchema;
  
  public OceanDocumentComparator(CSortFields sortFields, int nullBehavior, IndexSchema indexSchema) throws Exception {
    this.sortFields = sortFields;
    this.nullBehavior = nullBehavior;
    this.indexSchema = indexSchema;
    collators = createCollators(sortFields, indexSchema);
  }
  
  private static Collator[] createCollators(final CSortFields sortFields, IndexSchema indexSchema) throws Exception {
    if (sortFields == null) return null;
    Collator[] collators = new Collator[sortFields.size()];
    for (int i=0; i < sortFields.size(); ++i) {
      FieldType fieldType = indexSchema.getField(sortFields.get(i).field).getFieldType();
      if (fieldType instanceof LocalizedFieldType) {
        LocalizedFieldType localizedFieldType = (LocalizedFieldType)fieldType;
        collators[i] = Collator.getInstance(localizedFieldType.getLocale());
      }
    }
    return collators;
  }
  
  public int compareCollator(int index, Comparable s1, Comparable s2) {
    if (collators[index] != null) {
      return collators[index].compare(s1, s2);
    } else {
      return s1.compareTo(s2);
    }
  }
  
  public int compare(OceanDocument document1, OceanDocument document2) {
    int rtn = 0;
    int ctr = 0;
    int columnOrder;
    int compareCtr;
    
    while (rtn == 0 && ctr < sortFields.size()) {
      // The first object to compare.
      Comparable comparableOne;
      Comparable comparableTwo;
      
      final CSortField sortField = sortFields.get(ctr);
      final String field = sortField.field;
      
      comparableOne = (Comparable)document1.get(field);
      comparableTwo = (Comparable)document2.get(field);
      
      if (sortField.reverse) {
        columnOrder = DESCENDING_ORDER;
      } else {
        columnOrder = ASCENDING_ORDER;
      }
      // Compare the objects.
      if (comparableOne != null && comparableTwo != null) {
        if (columnOrder == ASCENDING_ORDER) {
          rtn = compareCollator(ctr, comparableOne, comparableTwo);
        } else {
          rtn = compareCollator(ctr, comparableTwo, comparableOne);
        }
      } else {
        if (nullBehavior == NULLS_ARE_INVALID) {
          throw new IllegalStateException("Null data values are not valid.");
        } else if (comparableOne == null && comparableTwo != null) {
          if (columnOrder == ASCENDING_ORDER) {
            rtn = -1;
          } else {
            rtn = 1;
          }
          if (nullBehavior == NULLS_ARE_GREATEST) {
            rtn = rtn * -1;
          }
        } else if (comparableOne != null && comparableTwo == null) {
          if (columnOrder == ASCENDING_ORDER) {
            rtn = 1;
          } else {
            rtn = -1;
          }
          if (nullBehavior == NULLS_ARE_GREATEST) {
            rtn = rtn * -1;
          }
        } else {
          rtn = 0;
        }
      }
      ctr++;
    }
    return rtn;
  }
}
